import { ConnectDB, IConnectOpt } from './connect'

export interface ITableOptions {
  tableName: string
  option: { keyPath?: string; autoIncrement?: boolean }
  indexs: Array<{
    key: string // *索引名
    option?: {
      // 索引配置，此处表示该字段不允许重复
      unique?: boolean
    }
  }>
}

export class Table extends ConnectDB {
  constructor(opt: IConnectOpt) {
    super(opt)
  }
  /** 创建表
   *
   * 初始化 / 新增表， return 创建结果
   *
   * 表已存在， reutrn 连接结果
   */
  protected async createTable(opts: ITableOptions[]) {
    let db = this.db
    let objectStore: IDBObjectStore
    let res: Promise<any>[] = []
    // 是否创建新表
    let isCreate: boolean = false

    opts.forEach((opt) => {
      try {
        if (!db.objectStoreNames.contains(opt.tableName)) {
          isCreate = true

          objectStore = db.createObjectStore(opt.tableName, opt.option)

          opt?.indexs?.forEach((item) => {
            objectStore.createIndex(item.key, item.key, item.option)
          })
        } else {
          res.push(Promise.resolve(true))
        }
      } catch (error) {
        res.push(Promise.reject(false))
      }
    })

    if (isCreate) {
      return Promise.all([
        new Promise((resolve, reject) => {
          objectStore.transaction.oncomplete = function (event) {
            // 不论创建几张表， 这里只调用一次
            resolve(event)
          }

          objectStore.transaction.onerror = function (event) {
            reject(event)
          }
          objectStore.transaction.onabort = function (event) {
            reject(event)
          }
        })
      ])
    } else {
      return Promise.all(res)
    }
  }
}

/**
 * 表操作基类
 */
export class BaseTable {
  public db!: IDBDatabase
  /** id 查找数据 */
  protected async getById(table: string, key: string | number) {
    return new Promise((resolve, reject) => {
      var transaction = this.db.transaction([table], 'readwrite')
      var objectStore = transaction.objectStore(table)
      var request = objectStore.get(key)

      request.onerror = function (evn: Event) {
        reject(false)
      }

      request.onsuccess = function (evn: Event) {
        resolve(request.result)
      }
    })
  }

  /** 主键 查找数据 */
  protected async getByIndex(
    table: string,
    index: string,
    key: string | number
  ) {
    return new Promise((resolve, reject) => {
      var request = this.db
        .transaction([table], 'readwrite')
        .objectStore(table)
        .index(index)
        .get(key)

      request.onerror = function (evn: Event) {
        reject(false)
      }

      request.onsuccess = function (evn: Event) {
        resolve(request.result)
      }
    })
  }

  /** 获取所有 */
  protected async getAll(table: string) {
    return new Promise((resolve, reject) => {
      var request = this.db
        .transaction([table], 'readwrite')
        .objectStore(table)
        .getAll()

      request.onerror = function (evn: Event) {
        reject(false)
      }

      request.onsuccess = function (evn: Event) {
        resolve(request.result)
      }
    })
  }

  /** 添加数据 */
  protected async add(table: string, data: {}) {
    return new Promise((resolve, reject) => {
      var request = this.db
        .transaction([table], 'readwrite')
        .objectStore(table)
        .add(data)

      request.onsuccess = function (event) {
        resolve(request.result)
      }

      request.onerror = function (event) {
        reject(event)
      }
    })
  }

  /** 更新数据 */
  protected async put(table: string, data: {}): Promise<any> {
    return new Promise((resolve, reject) => {
      var request = this.db
        .transaction([table], 'readwrite')
        .objectStore(table)
        .put(data)

      request.onsuccess = function (event) {
        resolve(request.result)
      }

      request.onerror = function (event) {
        reject(event)
      }
    })
  }

  /** 删除数据 */
  protected async del(table: string, id: number) {
    return new Promise((resolve, reject) => {
      var request = this.db
        .transaction([table], 'readwrite')
        .objectStore(table)
        .delete(id)

      request.onsuccess = function (event) {
        resolve(request.result)
      }

      request.onerror = function (event) {
        reject(event)
      }
    })
  }
}
